
#include <cstdio>
#include <BMap>
#include <BState>
#include <BFile>
#include "IWriter.h"
#include "member_BResource.h"
#include "member_BWidget.h"
#include "member_BImage.h"
#include "member_BStyle.h"

using namespace BWE;

#define REGIST_CLASS(sign, name)\
	signMap[#name] = sign;

#define REGIST_OBJECT(sign, name)\
	writeMap[sign] = (Write)&IWriter::write##name;\
	textMap[sign] = #name;\
	REGIST_CLASS(sign, B##name)

#define REGIST_VALUE(sign, name)\
	textMap[sign] = #name;

#define stack_up	(stack.top().sign)
#define def #define
#define DEFINE(sign, number) def sign number

IWriter::IWriter()
{
	REGIST_OBJECT(SIGN_SCENE, Scene);
	REGIST_OBJECT(SIGN_NODE, Node);
	REGIST_OBJECT(SIGN_LIGHT, Light);
	REGIST_OBJECT(SIGN_CAMERA, Camera);
	REGIST_OBJECT(SIGN_MESH, Mesh);
	REGIST_OBJECT(SIGN_GEOMETRY, Geometry);
	REGIST_OBJECT(SIGN_MATERIAL, Material);
	REGIST_OBJECT(SIGN_TEXTURE, Texture);
	REGIST_OBJECT(SIGN_PROGRAM, Program);
	REGIST_OBJECT(SIGN_IMAGE, Image);
	REGIST_OBJECT(SIGN_STATE, State);
	REGIST_OBJECT(SIGN_CONE, Cone);
	REGIST_OBJECT(SIGN_CUBE, Cube);
	REGIST_OBJECT(SIGN_CYLINDER, Cylinder);
	REGIST_OBJECT(SIGN_SPHERE, Sphere);
	REGIST_OBJECT(SIGN_TORUS, Torus);
	REGIST_OBJECT(SIGN_SURFACE, Surface);
	REGIST_OBJECT(SIGN_WIDGET, Widget);
	REGIST_OBJECT(SIGN_FONT, Font);
	REGIST_OBJECT(SIGN_CURSOR, Cursor);
	REGIST_OBJECT(SIGN_PALETTE, Palette);
	REGIST_OBJECT(SIGN_BUTTON, Button);
	REGIST_OBJECT(SIGN_SLIDER, Slider);
	REGIST_OBJECT(SIGN_COMBOBOX, ComboBox);
	REGIST_OBJECT(SIGN_CheckBox, CheckBox);
	REGIST_OBJECT(SIGN_SpinBox, SpinBox);
	REGIST_OBJECT(SIGN_LineEdit, LineEdit);
	REGIST_OBJECT(SIGN_TextEdit, TextEdit);
	REGIST_OBJECT(SIGN_TreeWidget, TreeWidget);
	REGIST_OBJECT(SIGN_ListWidget, ListWidget);
	REGIST_OBJECT(SIGN_TableWidget, TableWidget);
	REGIST_OBJECT(SIGN_ScrollBar, ScrollBar);
	REGIST_OBJECT(SIGN_ScrollWidget, ScrollWidget);
	REGIST_OBJECT(SIGN_Label, Label);
	REGIST_OBJECT(SIGN_Menu, Menu);
	REGIST_OBJECT(SIGN_MenuBar, MenuBar);
	REGIST_OBJECT(SIGN_Dialog, Dialog);
	REGIST_OBJECT(SIGN_GroupBox, GroupBox);
	REGIST_OBJECT(SIGN_Splitter, Splitter);
	REGIST_OBJECT(SIGN_TabWidget, TabWidget);
	REGIST_OBJECT(SIGN_Viewer, Viewer);

	REGIST_VALUE(SIGN_NAME, Name);
	REGIST_VALUE(SIGN_ENABLE, Enable);
	REGIST_VALUE(SIGN_MASK, Mask);
	REGIST_VALUE(SIGN_VISIBLE, Visible);
	REGIST_VALUE(SIGN_MATRIX, Matrix);
	REGIST_VALUE(SIGN_RECT, Rect);
	REGIST_VALUE(SIGN_SPACE, Space);
	REGIST_VALUE(SIGN_LIGHTING, Lighting);
	REGIST_VALUE(SIGN_DEPTHTEST, DepthTest);
	REGIST_VALUE(SIGN_LINESMOOTH, LineSmooth);
	REGIST_VALUE(SIGN_LINEWIDTH, LineWidth);
	REGIST_VALUE(SIGN_POINTSMOOTH, PointSmooth);
	REGIST_VALUE(SIGN_POINTSIZE, PointSize);
	REGIST_VALUE(SIGN_POLYGONMODE, PolygonMode);
	REGIST_VALUE(SIGN_CULLBACK, CullBack);
	REGIST_VALUE(SIGN_BASESIZE, BaseSize);
	REGIST_VALUE(SIGN_ROWCOUNT, RowCount);
	REGIST_VALUE(SIGN_COLUMNCOUNT, ColumnCount);
	REGIST_VALUE(SIGN_ROW, Row);
	REGIST_VALUE(SIGN_COLUMN, Column);
	REGIST_VALUE(SIGN_VERTICES, Vertices);
	REGIST_VALUE(SIGN_NORMALS, Normals);
	REGIST_VALUE(SIGN_TEXCOORDS, TexCoords);
	REGIST_VALUE(SIGN_FACES, Faces);
	REGIST_VALUE(SIGN_AMBIENT, Ambient);
	REGIST_VALUE(SIGN_DIFFUSE, Diffuse);
	REGIST_VALUE(SIGN_SPECULAR, Specular);
	REGIST_VALUE(SIGN_EMISSION, Emission);
	REGIST_VALUE(SIGN_SHININESS, Shininess);
	REGIST_VALUE(SIGN_ATTENUATION, Attenuation);
	REGIST_VALUE(SIGN_ATTENUATION2, Attenuation2);
	REGIST_VALUE(SIGN_POSITION, Position);
	REGIST_VALUE(SIGN_CENTER, Center);
	REGIST_VALUE(SIGN_UP, Up);
	REGIST_VALUE(SIGN_WIDTH, Width);
	REGIST_VALUE(SIGN_NEAR, Near);
	REGIST_VALUE(SIGN_FAR, Far);
	REGIST_VALUE(SIGN_BLEND, Blend);
	REGIST_VALUE(SIGN_BLENDCOLOR, BlendColor);
	REGIST_VALUE(SIGN_FILTER, Filter);
	REGIST_VALUE(SIGN_WRAP, Wrap);
	REGIST_VALUE(SIGN_MIPMAP, Mipmap);
	REGIST_VALUE(SIGN_FILENAME, FileName);
	REGIST_VALUE(SIGN_FORMAT, Format);
	REGIST_VALUE(SIGN_SIZE, Size);
	REGIST_VALUE(SIGN_PIXELS, Pixels);
	REGIST_VALUE(SIGN_TITLE, Title);
	REGIST_VALUE(SIGN_TOOLTIP, Tip);
	REGIST_VALUE(SIGN_MODAL, Modal);
	REGIST_VALUE(SIGN_POSITION, Position);
	REGIST_VALUE(SIGN_MINSIZE, MinSize);
	REGIST_VALUE(SIGN_MAXSIZE, MaxSize);
	REGIST_VALUE(SIGN_STRETCH, Stretch);
	REGIST_VALUE(SIGN_SIZEPOLICY, Policy);
	REGIST_VALUE(SIGN_BORDER, Border);
	REGIST_VALUE(SIGN_PERCH, Perch);
	REGIST_VALUE(SIGN_MARGIN, Margin);
	REGIST_VALUE(SIGN_COLOR, Color);
}
IWriter::~IWriter()
{

}

bool IWriter::writeObject(const BObject* object, const BString& fileName)
{
	if (!object)
		return false;

	BString ext = fileName.ext();
	ext.lower();

	if (ext == "widget" && !dynamic_cast<const BWidget*>(object))
		return false;
	if (ext == "node" && !dynamic_cast<const BNode*>(object))
		return false;
	if (ext == "scene" && !dynamic_cast<const BScene*>(object))
		return false;
	if (ext == "image" && !dynamic_cast<const BImage*>(object))
		return false;
	if (ext == "shape" && !dynamic_cast<const BShape*>(object))
		return false;
	if (ext == "shape" && !dynamic_cast<const BShape*>(object))
		return false;
	if (ext == "material" && !dynamic_cast<const BMaterial*>(object))
		return false;

	stack.clear();
	BFile file(fileName);
	if (!file.open(BFile::Mode_Write))
		return false;
	stream = &file;

	return write(object);
}

bool IWriter::write(const BObject* object)
{
	if (!object)
		return false;
	int sign = signMap(object->className());
	if (!sign)
		return false;
	Block block;
	block.sign = sign;
	block.begin = stream->offset();
	stream->wmove(sizeof(Block));

	Write write = writeMap(sign);
	if (!write)
	{
		printf("Write : %s -- No write method.\n", textMap(sign));
		return false;
	}
	if (!(this->*write)(object))
	{
		printf("Write : %s -- write faild.\n", textMap(sign));
		return false;
	}

	block.end = stream->offset();
	block.size = block.end - block.begin - sizeof(Block);
	stream->seek(block.begin);
	stream->write(block);
	stream->seek(block.end);
	return true;
}

bool IWriter::writeObjectData(const BObject* object)
{
	if (!object)
		return false;
	write(SIGN_NAME, object->name());
	write(SIGN_ENABLE, object->able());
	return true;
}
bool IWriter::writeNodeData(const BNode* node)
{
	if (!node)
		return false;
	write(SIGN_VISIBLE, node->visible());
	write(SIGN_MATRIX, node->matrix());
	for (int i = 0; i < node->shapeCount(); i++)
	{
		const BShape* shape = node->shape(i);
		write(shape);
	}
	return true;
}
bool IWriter::writeShapeData(const BShape* shape)
{
	if (!shape)
		return false;
	write(SIGN_SPACE, shape->space());
	write(shape->material());
	write(shape->texture());
	write(shape->program());
	return true;
}
bool IWriter::writeMeshData(const BMesh* mesh)
{
	if (!mesh)
		return false;
	const BVectorArray* vertices = mesh->vertices();
	if (vertices)
	{
		write(SIGN_VERTICES, *vertices);
	}
	const BVectorArray* normals = mesh->normals();
	if (normals)
	{
		write(SIGN_NORMALS, *normals);
	}
	const BFaceArray* faces = mesh->faces();
	if (faces)
	{
		write(SIGN_FACES, *faces);
	}
	const BCoordArray* texCoords = mesh->texCoords();
	if (texCoords)
	{
		write(SIGN_TEXCOORDS, *texCoords);
	}
	return true;
}
bool IWriter::writeTextureData(const BTexture* texture)
{
	if (!texture)
		return false;

	write(SIGN_BLEND, texture->blend());
	write(SIGN_BLENDCOLOR, texture->blendColor());
	write(SIGN_FILTER, texture->filter());
	write(SIGN_WRAP, texture->wrap());
	write(SIGN_MIPMAP, texture->mipmap());

	return true;
}
bool IWriter::writeWidgetData(const BWidget* widget)
{
	if (!widget)
		return false;
	write(SIGN_TOOLTIP, widget->tips());
	write(SIGN_MODAL, widget->modal());
	write(SIGN_POSITION, widget->pos());
	write(SIGN_SIZE, widget->size());
	write(SIGN_MINSIZE, widget->minSize());
	write(SIGN_MAXSIZE, widget->maxSize());
	write(SIGN_STRETCH, widget->sizeStretch());
	write(SIGN_SIZEPOLICY, widget->sizePolicy());
	write(SIGN_BORDER, widget->border());
	write(SIGN_PERCH, widget->perchs());
	write(SIGN_MARGIN, widget->margins());

	write(widget->cursor());
	write(widget->style());
	write(widget->font());
	write(widget->style());

	for (auto child : widget_member(widget)->children)
		write(child);
	return true;
}

bool IWriter::writeNode(const BNode* node)
{
	writeObjectData(node);
	writeNodeData(node);
	return true;
}
bool IWriter::writeLight(const BLight* light)
{
	writeObjectData(light);
	writeNodeData(light);
	write(SIGN_AMBIENT, light->ambient());
	write(SIGN_DIFFUSE, light->diffuse());
	write(SIGN_SPECULAR, light->specular());
	write(SIGN_ATTENUATION, light->attenuation());
	write(SIGN_ATTENUATION2, light->attenuation2());
	return true;
}
bool IWriter::writeCamera(const BCamera* camera)
{
	writeObjectData(camera);
	write(SIGN_POSITION, camera->position());
	write(SIGN_CENTER, camera->center());
	write(SIGN_UP, camera->up());
	write(SIGN_NEAR, camera->near());
	write(SIGN_FAR, camera->far());
	return true;
}
bool IWriter::writeScene(const BScene* scene)
{
	writeObjectData(scene);
	for (int i = 0; i < scene->nodeCount(); i++)
	{
		const BNode* node = scene->node(i);
		write(node);
	}
	return true;
}
bool IWriter::writeShape(const BShape* shape)
{
	writeObjectData(shape);
	writeShapeData(shape);
	return true;
}
bool IWriter::writeMesh(const BMesh* mesh)
{
	writeObjectData(mesh);
	writeShapeData(mesh);
	writeMeshData(mesh);
	return true;
}
bool IWriter::writeGeometry(const BGeometry* geometry)
{
	if (!geometry)
		return false;
	writeObjectData(geometry);
	writeShapeData(geometry);
	const BVectorArray* vertices = geometry->vertices();
	if (vertices)
	{
		write(SIGN_VERTICES, *vertices);
	}
	const BVectorArray* normals = geometry->normals();
	if (normals)
	{
		write(SIGN_NORMALS, *normals);
	}
	write(geometry->material());
	return true;
}
bool IWriter::writeState(const BState* state)
{
	writeObjectData(state);
	write(SIGN_LIGHTING, state->lighting());
	write(SIGN_DEPTHTEST, state->depthTest());
	write(SIGN_LINESMOOTH, state->lineSmooth());
	write(SIGN_LINEWIDTH, state->lineWidth());
	write(SIGN_POINTSMOOTH, state->pointSmooth());
	write(SIGN_POINTSIZE, state->pointSize());
	write(SIGN_POLYGONMODE, state->polygonMode());
	write(SIGN_CULLBACK, state->cullBackface());
	return true;
}
bool IWriter::writeMaterial(const BMaterial* material)
{
	writeObjectData(material);
	write(SIGN_AMBIENT, material->ambient());
	write(SIGN_DIFFUSE, material->diffuse());
	write(SIGN_SPECULAR, material->specular());
	write(SIGN_EMISSION, material->emission());
	write(SIGN_SHININESS, material->shininess());
	return true;
}
bool IWriter::writeTexture(const BTexture* texture)
{
	return writeTextureData(texture);
}
bool IWriter::writeProgram(const BProgram* program)
{
	writeObjectData(program);
	return true;
}
bool IWriter::writeImage(const BImage* image)
{
	writeObjectData(image);
	writeTextureData(image);
	write(SIGN_FORMAT, image->format());
	write(SIGN_SIZE, image->size());
	write(SIGN_PIXELS, *image->pixels());
	return true;
}
bool IWriter::writeCone(const BCone* cone)
{
	return true;
}
bool IWriter::writeCube(const BCube* cube)
{
	return true;
}
bool IWriter::writeCylinder(const BCylinder* cylinder)
{
	return true;
}
bool IWriter::writeSphere(const BSphere* sphere)
{
	return true;
}
bool IWriter::writeTorus(const BTorus* torus)
{
	return true;
}
bool IWriter::writeSurface(const BSurface* surface)
{
	writeObjectData(surface);
	writeShapeData(surface);
	write(SIGN_ORIGIN, surface->origin());
	write(SIGN_RIGHT, surface->right());
	write(SIGN_FRONT, surface->front());
	write(SIGN_RIGHTSEGMENT, surface->rightSegment());
	write(SIGN_FRONTSEGMENT, surface->frontSegment());
	return true;
}

bool IWriter::writeWidget(const BWidget* widget)
{
	writeObjectData(widget);
	writeWidgetData(widget);
	return true;
}
bool IWriter::writePalette(const BStyle* style)
{
	writeObjectData(style);
	write(SIGN_COLORMAP, style_member(style)->colorMap);
	return true;
}
bool IWriter::writeCursor(const BCursor* cursor)
{
	if (!cursor)
		return false;
	return true;
}
bool IWriter::writeFont(const BFont* font)
{
	writeObjectData(font);

	return true;
}
bool IWriter::writeButton(const BButton* button)
{
	writeObjectData(button);
	writeWidgetData(button);
	write(SIGN_ALIGN, button->align());
	write(SIGN_ICONSIZE, button->iconSize());
	write(button->image());
	return true;
}
bool IWriter::writeSlider(const BSlider* slider)
{
	writeObjectData(slider);
	writeWidgetData(slider);
	write(SIGN_ORITENTION, slider->orientation());
	write(SIGN_VALUE, slider->value());
	write(SIGN_RANGE, slider->range());
	write(SIGN_STEP, slider->step());
	return true;
}
bool IWriter::writeScrollArea(const BScrollArea* scrollArea)
{
	return true;
}
bool IWriter::writeComboBox(const BComboBox* comboBox)
{
	return true;
}
bool IWriter::writeCheckBox(const BCheckBox* checkBox)
{
	return true;
}
bool IWriter::writeSpinBox(const BSpinBox* spinBox)
{
	return true;
}
bool IWriter::writeLineEdit(const BLineEdit* lineEdit)
{
	return true;
}
bool IWriter::writeTextEdit(const BTextEdit* textEidt)
{
	return true;
}
bool IWriter::writeTreeWidget(const BTreeWidget* treeWidget)
{
	return true;
}
bool IWriter::writeListWidget(const BListWidget* listWidget)
{
	return true;
}
bool IWriter::writeTableWidget(const BTableWidget* tableWidget)
{
	return true;
}
bool IWriter::writeScrollBar(const BScrollBar* scrollBar)
{
	return true;
}
bool IWriter::writeScrollWidget(const BScrollWidget* scrollWidget)
{
	return true;
}
bool IWriter::writeLabel(const BLabel* label)
{
	return true;
}
bool IWriter::writeMenu(const BMenu* menu)
{
	return true;
}
bool IWriter::writeMenuBar(const BMenuBar* menuBar)
{
	return true;
}
bool IWriter::writeDialog(const BDialog* dialog)
{
	return true;
}
bool IWriter::writeGroupBox(const BGroupBox* groupBox)
{
	return true;
}
bool IWriter::writeSplitter(const BSplitter* splitter)
{
	return true;
}
bool IWriter::writeTabWidget(const BTabWidget* tabWidget)
{
	return true;
}
bool IWriter::writeViewer(const BViewer* viewer)
{
	writeObjectData(viewer);
	writeWidgetData(viewer);
	const BCamera* camera = viewer->camera();
	if (camera)
	{

	}
	return true;
}

void IWriter::print()
{
	BString output('\t', stack.size());
	output << textMap(block.sign);
	puts(output.cstr());
}
void IWriter::print(const char* cstr)
{
	BString output('\t', stack.size());
	output << textMap(block.sign);
	output << " : " << cstr;
	puts(output.cstr());
}
void IWriter::print(const BString& str)
{
	BString output('\t', stack.size());
	output << textMap(block.sign);
	output << " : " << str;
	puts(output.cstr());
}

